package cn.netjava.robo3d;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import cn.netjava.robo3d.actions.AddOilrateAction;
import cn.netjava.robo3d.actions.CaseMateLeftRightAction;
import cn.netjava.robo3d.actions.KeyNodeBackwardAction;
import cn.netjava.robo3d.actions.KeyNodeForwardAction;
import cn.netjava.robo3d.actions.KeyNodeStrafeLeftAction;
import cn.netjava.robo3d.actions.KeyNodeStrafeRightAction;
import cn.netjava.robo3d.actions.LeftRightAction;
import cn.netjava.robo3d.actions.OilrateDriftAction;
import cn.netjava.robo3d.device.Bullet;
import cn.netjava.robo3d.device.CaseMate;
import cn.netjava.robo3d.device.CaterPilar;
import cn.netjava.robo3d.device.FireGun;
import cn.netjava.robo3d.event.HitByBulletEvent;
import cn.netjava.robo3d.event.HitByFireEvent;
import cn.netjava.robo3d.event.HitWallEvent;
import cn.netjava.robo3d.event.ImpactCarEvent;

import com.jme.bounding.BoundingBox;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.shape.Arrow;
import com.jme.scene.shape.Box;
import com.jme.system.DisplaySystem;
import com.jme.util.export.binary.BinaryImporter;
import com.jmex.audio.AudioSystem;
import com.jmex.audio.AudioTrack;
import com.jmex.audio.AudioTrack.TrackType;
import com.jmex.effects.particles.ParticleMesh;
import com.jmex.model.converters.FormatConverter;
import com.jmex.model.converters.MaxToJme;
import com.jmex.terrain.TerrainBlock;

/**
 *
 * @desc:所有Tank的父类
 * @project:蓝杰3D机器坦克平台
 * @author: 余斌 www.NetJava.cn
 * @createDate:2009-8-22-下午12:29:32
 */
public class RoboTank extends Node implements Runnable {
	public static int forwardflag = 1;
	public static int backwardflag = -1;
	private DisplaySystem display; // 显示器
	private float oil; // 油量
	private int Gear; // 油门档位
	private float oilrate; // 油门大小
	private float oilweight; // 油的质量
	private final float engineable=12;  //终极油门限制
	private float Maxoilrate; // 油门最大限制
	private float T; // 拉力,由发动机产生
	private float F; // 前进 合力
	private Vector3f recoil=new Vector3f(0,0,0);//炮弹后座力

	private float acceleration; // 加速度
	public float speed = 0; // 速度
	private float vcross=0;   //垂直方向上的速度

	private float ycross=0;   //垂直方向上的高度
	private float g=10;        //重力加速度
	// ///////////////控制器对象
	private OilrateDriftAction oilratedrift;
	private AddOilrateAction addoilrate;
	private KeyNodeStrafeLeftAction strafeleft;
	private KeyNodeStrafeRightAction straferight;
	private LeftRightAction left;
	private LeftRightAction right;
	private KeyNodeForwardAction forward;
	private KeyNodeBackwardAction backward;

	private CaseMateLeftRightAction caserotaright;
	private CaseMateLeftRightAction caserotaleft;
	// private
	// private
	private float blood = 200; // 血量
	private float score = 0; // 得分
	private int bulletnum = 500; // 子弹总数
	private float firenum = 50; // 喷火枪个数

	private int byshoot = 0; // 中弹次数
	private float byfire = 0; // 被火烧次数
	private float mass; // 车身的质量
	private float totalmass; // 车的总质量
	private float pressionforce; // 对地正向压力
	private float frictionfactor; // 摩擦因数
	private float friction; // 车受到的摩擦力
	private Box base; // 基座模型
	private CaseMate casemate; // 炮塔; // 火苗
	private Arrow casematearrow;
	private FireGun firegun; // 喷火枪
	private ParticleMesh fire;
	private boolean endfireflag = false; // 停止发火标记
	private float caseAlpha = 0; // 炮塔旋转角度,
	private Vector3f gundirection = new Vector3f().ZERO; // 炮塔指向
	private Input input;
    private int direction; // 前进或后退档
	private Vector3f impactforce = new Vector3f(); // 碰撞外力
	//	private float sideforce = 0; // 侧向碰撞力
	private int impacttimecount = 0; // 碰撞力计时
	private float sideacceleration = 0; // 侧向加速度
	private float sidespeed = 0; // 侧向速度
	private float sidefactor = 0.2f; // 侧向摩擦因数,很大
	private float sidefriction = 0; // 侧向摩擦力
	private float sideT = 0; // 侧向合力;
	private Vector3f leftdirection; // 向左向量,侧向以这个为正方向

	private CaterPilar leftcater; // 左履带
	private CaterPilar rightcater; // 右履带
	private float turnalpha = 0; // 坦克转过角度
	private Vector3f normal; // 坦克位置的法线
	private TerrainBlock tb; // 地形对象
	private Vector3f vertical; // 水平面法线
	private Vector3f cardirection; // 坦克指向
	private Vector3f slope; // 斜坡方向,也即重力分力方向
	private float Tangle; // 坦克正方向与斜坡的夹角

	private float angle; // 水平面法线与地面法线的夹角;即坡度
	private float tiltangle = 0; // 物体与斜坡倾角
	private boolean startlistener; // 监控器启动开关
	private HitByFireEvent hitbyfireevent; // 被火烧事件
	private ImpactCarEvent impactcarevent; // 碰撞事件
	private boolean startdetect = false; // 探测相撞开关
	private boolean getdistanceflag = false; // 取得距离开关
	private boolean isleave = false; // 坦克相离 开关
	private float distance1 = 0; // 前一帧与最近坦克距离大小
	private float distance2 = 0; // 当前
	private TankInformation info;
	private List<TankInformation> allothertanksinfo; // 引用所有其它坦克
	private static float maxvolume=0.6f;             //最大声音
	private float soundvolume=maxvolume;  //声音大小
	private float volumelimitdistance=120f;  //声音限制范围       
	private AudioTrack   hitbybulletsound;            //声音对象
	private AudioTrack   shootsound; 
	private AudioTrack   changegearsound; 
	private AudioTrack   powersound; 
	private AudioTrack   movesound;
	private AudioTrack   jumpsound; 
	private AudioTrack   impactfloorsound; 
	private AudioTrack   impactcarsound; 
//	private AudioTrack   ; 
//	private AudioTrack   ; 
	
	private List<Bullet> bullets; // 坦克的子弹池
	private HitByBulletEvent hitbybulletevent; // 中弹事件
//	private TargetFeild targetfeild;
//	private boolean havatargetfeild=false;     //是否具有靶框

	/**
	 * 调整姿态，和斜面保持平行
	 */
	private int i = 0;

	/**
	 * 刷新交换属性,通过这个与其它坦克通信
	 */
	private boolean scoreflag = true;

	/**
     *
     */
	public RoboTank() {
		inittank();
	}

	/**
	 *
	 * @param carnode
	 */
	public RoboTank(String name) {
		this.setName(name);
		inittank();

	}

	/**
	 * 加入所有其它坦克信息
	 *
	 * @param alltank所有坦克
	 *            ,包括自己
	 */
	public void addallothertanksinfo(List<TankInformation> alltanksinfo) {
		ArrayList<TankInformation> tempallinfo = new ArrayList();
		for (int i = 0; i < alltanksinfo.size(); i++) {
			if (!info.equals(alltanksinfo.get(i))) {
				tempallinfo.add(alltanksinfo.get(i));
			}
		}
		allothertanksinfo = tempallinfo;
	}

	/**
	 * 累加车体旋转角度
	 *
	 * @param
	 */
	public void addAlpha(float step) {
		this.turnalpha = this.turnalpha + step;
	}

	// 加血
	private void addblood() {

	}

	/**
	 * 累加炮塔旋转角度,相对于车体基座的方向
	 */
	public void addcaseAlpha(float step) {
		// 炮塔的这个转角是相对于车体,还要转换为相对地面
		this.caseAlpha = this.caseAlpha + step;
		// //////////////根据转过角度,设置炮塔指向
		// System.out.println("炮塔旋转角度:"+caseAlpha);
		// System.out.println("车体旋转角度:"+turnalpha);
	}

	// 加生命
	private void addlife() {

	}

	// 加油
	private void addoil() {

	}

	/**
	 * 累加油门值
	 *
	 * @param step
	 */
	public void addoilrate(float step) {
		if (oilrate < Maxoilrate && oil >= 1.0f) { // 不让油门超出最大值,并且要有油
			oilrate = oilrate + step;
			keepoilrate();
		}
	}

	// 加分
	private void addscore() {

	}

	public void ajustpose() {
		// 调整车体，根据当前left,cardirect
		// 更新left,cardirect,gundirect
		// 地面法线确定一个平面，以left为轴旋转使cardirect平行于这个平面
		// 再以cardirect为轴，使left平行于这个平面
		// cardirect和gundirect围绕车体法线旋转
		cardirection.y = 0;
		cardirection.x = ((float) Math.sin(turnalpha) * 1);
		cardirection.z = ((float) Math.cos(turnalpha) * 1);
		cardirection = getunit(cardirection);

		leftdirection.y = 0;
		leftdirection.x = cardirection.z;
		leftdirection.z = -cardirection.x;

		// 设置炮口指向
		//根据向量先反求alpha
		//caseAlpha=-FastMath.acos(cardirection.dot(gundirection));
		if(!getName().equals("player")){//权宜之计
			gundirection.y = 0;
			gundirection.x = ((float) Math.sin(turnalpha + caseAlpha) * 1);
			gundirection.z = ((float) Math.cos(turnalpha + caseAlpha) * 1);
			gundirection = getunit(gundirection);
			float temangle = normal.angleBetween(gundirection);
			gundirection.y = FastMath.tan(temangle - FastMath.PI / 2);
			gundirection = getunit(gundirection);
		}
//		if(casematearrow!=null){
//			if(!this.hasChild(casematearrow))this.attachChild(casematearrow);
//			casematearrow.setLocalTranslation(localTranslation);
//			//casematearrow.getLocalTranslation().y=casematearrow.getLocalTranslation().y+0.5f;
//			casematearrow.rotateUpTo(gundirection);
//			System.out.println("箭头非空:"+getName());
//		}

		if (i != 0) {// 在第一次不执行这句
			this.rotateUpTo(normal); // 调整车体
		}
		i = 1;
	}

//	public void creategunarrow(){
//		casematearrow=new Arrow("gunarrow",300,20f);
//		this.attachChild(casematearrow);
//		this.updateWorldBound();
//	}

	/**
	 * 以一定速度后退
	 *
	 * @return
	 */
	public void backward(float speed) {
		backward.setSpeed(speed);
		backward.performAction(input.getevent());
	}

	// 刹车
	public void brake() {

	}

	/**
	 * 改变油门档位，调用一次改变一次，循环改变
	 *
	 * @param
	 */
	public void changeGear() {
		int gear = Gear + 1;
		if (gear > 3) {
			gear = gear - 3;
		}

		changegearsound.play();
		
		setGear(gear);
	}

	/**
	 * 控制油门,调用它将慢慢增加油门值
	 *
	 */
	public void controloilrate() {
		addoilrate.performAction(input.getevent());
		//carturn.play();
	}

	/**
	 * 创建车体基座模型
	 *
	 */
	public void createbase() {
		this.setLocalTranslation(new Vector3f(100, 0, 100));
		// this.attachChild(base); // jmetest/data/model/maggie.obj
		URL modelurl = RoboTank.class.getClassLoader().getResource(
				"cn/netjava/robo3d/model/FT17_BER/FT17BER_.3DS");
		FormatConverter converter = new MaxToJme();
		// Point the converter to where it will find the .mtl file from
		converter.setProperty("mtllib", modelurl);

		// This byte array will hold my .jme file
		ByteArrayOutputStream BO = new ByteArrayOutputStream();
		try {
			// Use the format converter to convert .obj to .jme
			converter.convert(modelurl.openStream(), BO);
			Node base = (Node) BinaryImporter.getInstance().load(
					new ByteArrayInputStream(BO.toByteArray()));
			// shrink this baby down some
			base.setLocalScale(0.0005f);
			base.setModelBound(new BoundingBox());
			base.updateModelBound();
			Quaternion qua = new Quaternion();
			qua.fromAngleAxis(-FastMath.PI / 2, new Vector3f(1, 0, 0));
			base.setLocalRotation(qua);
//			Quaternion qua2 = new Quaternion();
//			qua2.fromAngleAxis(FastMath.PI , new Vector3f(0, 1, 0));
//			base.setLocalRotation(qua2);
			base.setLocalTranslation(new Vector3f(0, -1.32f, 0));
			// Put her on the scene graph
			this.attachChild(base);
		} catch (IOException e) { // Just in case anything happens

			System.exit(0);
		}
		this.updateWorldBound();
	}

	public void createbullets(DisplaySystem display){
		bullets = new ArrayList(); // 创建子弹队列,20个子弹,只有激活才有用
		for (int i = 0; i < 20; i++) {
			Bullet bullet = new Bullet(info,display);
			bullets.add(bullet);
		}
	}

	/**
	 * 创建炮塔
	 */
	public void createcase(DisplaySystem display) {
		this.display = display;
		casemate = new CaseMate(display);
		firegun = new FireGun(display, casemate.getGeometry());
		fire = (ParticleMesh) firegun.getChild("fire");
		casemate.attachChild(firegun);
		this.attachChild(casemate);
	}

	/**
	 * 监控是否相撞,与帧同步
	 */
	private void detect() {
		// ////////相撞时判断两坦克是否处于离开状态
		if (getdistanceflag) {
			distance1 = impactcarevent.getdistance().distance(Vector3f.ZERO);
			float delta = distance1 - distance2;
			if (delta > 0) {
				isleave = true;
			}
			if (delta < 0) {
				isleave = false;
			}
			System.out.println("delta:" + delta);
			distance2 = distance1;
		}
		if (startdetect && impactcarevent.ishappen()) {// 如果撞墙事件发生,执行系统动作
			onimpactcar(impactcarevent);
			onimpactcarCore();
			getdistanceflag = true;

		}
		if (startdetect && !impactcarevent.ishappen()) {
			getdistanceflag = false;
		}
		// /////////////////////////////////////////////////////////////////////////////////////////
		// ///////////判断是否被烧
		if (startdetect && hitbyfireevent.ishappen()) {
			onhitbyfireCore();
			onhitbyfire(hitbyfireevent);
		}
		// //////////////////////////////////////////////////////////////////////////////////////////
		// ////////////判断是否中弹
		if (startdetect && hitbybulletevent.ishappen()) {
			onhitbybullet(hitbybulletevent);
			onhitbybulletCore();
		}

	}

	/**
	 * 停止喷火枪
	 */
	public void endfiregun() {
		endfireflag = true;
		casemate.detachChild(firegun);

	}

	// 爆炸
	private void explode() {

	}

	/**
	 * 启动火枪
	 *
	 */
	public void firegun() {
		endfireflag = false;
		fire
				.setSpeed(0.8f + Math.abs(speed * (float) Math.cos(caseAlpha)
						/ 20)); // 跟着坦克一起跑
		if (firenum <= 0) { // 没有子弹启不动
			endfireflag = true;
			firenum = 0;
			casemate.detachChild(firegun);
		} else {
			casemate.attachChild(firegun);
		}
		firenum = firenum - 0.04f;
	}

	/**
	 * 向前运动，参数为速度
	 *
	 * @return
	 */
	public void forward(float speed) {
		forward.setSpeed(speed);
		forward.performAction(input.getevent());
	}

	/**
	 * 得到所有其它坦克信息
	 *
	 * @return
	 */
	public List getallothertankinfo() {
		return allothertanksinfo;
	}

	/**
	 * 得到车体旋转角度
	 *
	 * @param
	 */
	public float getAlpha() {
		return turnalpha;
	}

	/**
	 * 得到坡度角
	 *
	 * @return
	 */
	public float getAngle() {
		return angle;
	}

	/**
	 *得到子弹队列
	 */
	public List getbullets() {
		return bullets;
	}

	public Vector3f getCardirection() {
		return cardirection;
	}

	/**
	 * 得到炮塔旋转角度
	 */
	public float getcaseAlpha() {
		return caseAlpha;
	}

	/**
	 * 得到炮塔对象
	 */
	public CaseMate getcasemate() {
		return casemate;
	}

	/**
	 * 得到油门档位
	 *
	 * @return
	 */
	public int getGear() {
		return Gear;
	}

	/**
	 * 得到炮塔指向
	 */
	public Vector3f getgundirection() {
		return gundirection;
	}
	public void setgundirection(Vector3f gundirection){
		this.gundirection=gundirection;
	}

	public TankInformation getinfo() {
		return info;
	}

	public Vector3f getLeftdirection() {
		return leftdirection;
	}

	/**
	 * 得到当前最大油门限制
	 *
	 * @return
	 */
	public float getMaxoilrate() {
		return Maxoilrate;
	}

	/**
	 * 得到车体所在位置的法线
	 *
	 * @param
	 */
	public Vector3f getNormal() {
		return normal;
	}

	/**
	 * 得到所剩油量
	 *
	 * @return
	 */
	public float getoil() {
		return oil;
	}

	/**
	 * 得到当前油门大小
	 *
	 * @return
	 */
	public float getoilrate() {
		return oilrate;
	}

	/**
	 * 得到前进速度
	 *
	 * @return
	 */
	public float getspeed() {
		return speed;
	}

	/**
	 * 得到单位向量
	 *
	 * @param vec
	 * @return
	 */
	public Vector3f getunit(Vector3f vec) {
		float length = (float) Math.sqrt(vec.x * vec.x + vec.y * vec.y + vec.z
				* vec.z);
		return vec.divide(length);
	}

	/**
	 * 初始化坦克参数
	 */
	private void inittank() {
		System.out.println("初始化战车:" + this.getName());

        //控制器
		oilratedrift = new OilrateDriftAction(this); // 油门自动减小对象
		addoilrate = new AddOilrateAction(this);
		strafeleft = new KeyNodeStrafeLeftAction(this);
		straferight = new KeyNodeStrafeRightAction(this);
		left = new LeftRightAction(this, LeftRightAction.left);
		right = new LeftRightAction(this, LeftRightAction.right);
		forward = new KeyNodeForwardAction(this);
		backward = new KeyNodeBackwardAction(this);
		caserotaright = new CaseMateLeftRightAction(this, -1);
		caserotaleft = new CaseMateLeftRightAction(this, 1);

		// 初始化基本参数
		oil = 600;
		oilrate = 0;
		this.setGear(1);
		acceleration = 0;
		mass = 400;
		frictionfactor = 0.03f;
		T = 0;
		F = 0;
		direction = forwardflag;
		normal = new Vector3f();
		vertical = new Vector3f(0, 1, 0);
		cardirection = new Vector3f(0, 0, -1);
		leftdirection = new Vector3f(-1, 0, 0);
		slope = new Vector3f();
		info = new TankInformation();
		startlistener = true; // 启动监听器
		this.setLocalScale(0.5f);
		refreshinfo();
		//创建声音
        createsound();
	}

	// 跳跃
	public void jump() {
        //只有和地面很近才能跳跃
		float characterMinHeight = tb.getHeight(this.getLocalTranslation());
		if(FastMath.abs(ycross-characterMinHeight-0.05f)<0.02f)
		{
			vcross=8f;
			jumpsound.play();
		}
	}

	/**
	 * 使油门保持在正常的范围内
	 *
	 */
	private void keepoilrate() {
		if (oilrate < 0) {
			oilrate = 0;
		}
		if (oilrate > this.Maxoilrate) {
			oilrate = Maxoilrate;
		}
	}

	/**
	 * 保持车体旋转角度在一定范围,以免溢出
	 *
	 */

	/**
	 * 使物体保持在地形上方
	 *
	 */
	private void keepthison(float time) {
        //地面高度
		float characterMinHeight = tb.getHeight(this.getLocalTranslation());

		//如果有跳跃，即有垂直速度了，否则位置贴地
		if(vcross!=0)
		{
		       vcross=vcross-1.5f*g*time;        //速度处理
		       ycross=ycross+vcross*time; //竖直位置处理
		       if(ycross<characterMinHeight) //防止掉到地面以下
		       {
		    	   ycross= characterMinHeight + 0.05f;
		       }
			   //如果离地面很近，而且有负值的速度，说明要撞地面了
		       if((FastMath.abs(ycross-characterMinHeight-0.05f)<0.02f)&&(vcross<0))
			   {
				   //速度反向并且衰减
		    	   vcross=-0.4f*vcross;
		    	   //如果速度很小了，速度置零
		    	   if(FastMath.abs(vcross)<1f)
		    	   {
		    		   vcross=0;
		    	   }
		    	   //撞地发声
		    	   impactfloorsound.play();
			   }
		}
		else
		{
			   	if (!Float.isInfinite(characterMinHeight)
					&& !Float.isNaN(characterMinHeight))
			   	{
				    ycross= characterMinHeight + 0.05f;
			    }
		}
        this.getLocalTranslation().y=ycross;
	}



	/**
	 * 以一定速度向左旋转炮塔
	 */
	public void leftcasemate(float speed) {
		caserotaleft.setActionSpeed(speed);
		caserotaleft.performAction(input.getevent());
	}

	// 降血
	private void lowerblood() {

	}

	// 减生命
	private void lowerlife() {

	}

	// 耗油
	private void loweroil() {

	}

	// 降分
	private void lowerscore() {

	}

	/**
	 * 油门漂移,油门大小慢慢下降
	 *
	 * @param step
	 */
	public void oilratedrift(float step) {
		if (oilrate > 0) {// 不能让它小于0
			oilrate = oilrate - step;
		}
		keepoilrate();
	}

	public void onhitbybullet(HitByBulletEvent evt) {
	}

	public void onhitbybulletCore() {
		System.out
				.println(name + ":中弹了  " + hitbybulletevent.getTotalbullets());
		blood = blood - hitbybulletevent.getTotalbullets();
		byshoot = hitbybulletevent.getTotalbullets();
		// 添加声音
		
		hitbybulletsound.play();
	}

	/**
	 * 被喷火枪烧
	 */
	public void onhitbyfire(HitByFireEvent evt) {

	}

	/**
	 *被喷火枪烧,系统动作
	 */
	public void onhitbyfireCore() {
		// System.out.println(name+":系统检测到 被烧了");
		blood = blood - 0.02f;
		byfire = byfire + 0.02f;
	}

	public void onhitwall(HitWallEvent evt) {
	}

	public void onhitwallCore() {

	}

	/**
	 * 事件方法 发生事件时,调用的方法
	 *
	 * @param evt
	 */
	public void onimpactcar(ImpactCarEvent evt) {
	}

	/**
	 * 当这一事件发生时,系统的应对方法
	 *
	 */
	public void onimpactcarCore() {
		blood = blood - 1;
		speed = impactcarevent.getimpactedspeed()[0];
		sidespeed = impactcarevent.getimpactedspeed()[1];
		if (isleave) { // 如果离开，设置碰撞速度
			// 投影到车指向方向
			float tempforwardspeed = impactcarevent.getdistance().dot(
					cardirection);
			speed = 7f * tempforwardspeed / Math.abs(tempforwardspeed);
			sidespeed = 0;
		}
		
//		坦克碰撞发声
		impactcarsound.play();
	}

	/**
	 * 暂停游戏
	 */
	public void pause(long time) {
		try {
			Thread.sleep(time);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void refreshinfo() {
		info.setName(this.getName());
		info.setF(F); // 合力
		info.setAcceleration(acceleration); // 加速度
		info.setSpeed(speed); // 速度
		info.setBlood(blood); // 血量
		if (scoreflag) {
			info.setScore(score); // 得分 ,因为分数要在这里用到,只能设一次,即引用一次
			System.out.println("fenshu");
			scoreflag = false;
		}
		info.setTotalmass(totalmass); // 车的总质量
		info.setNormal(normal); // 坦克位置的法线
		info.setCardirection(cardirection); // 坦克指向
		info.setSlope(slope); // 斜坡方向,也即重力分力方向
		info.setAngle(angle); // 水平面法线与地面法线的夹角;
		info.setLocaltranslation(this.getLocalTranslation());
		info.setBase(base);
		info.setfiregun(firegun);
		info.setendfireflag(endfireflag);
		info.setBullets(bullets);
		info.setCasealpha(caseAlpha);
		info.setBulletnum(bulletnum);
		info.setFirenum(firenum);
		info.setByshoot(byshoot);
		info.setByfire(byfire);
		info.setGundirection(gundirection);
		info.setLeftdirection(leftdirection);
	}

	/**
	 * 刷新车体所有受力,设置加速度(横向,纵向) 拉力,摩擦力(横向,纵向),合力,加速度(考虑重力的分力)
	 */
	private void refreshpower() {// 刷新所有力

		float extraforce; // 重力分力
		oilweight = oil / 60;
		totalmass = mass + oilweight; // 考虑油的损耗
		pressionforce = (float) (totalmass * 10 * Math.cos(angle));
		extraforce = (float) (totalmass * 10 * Math.sin(angle));
		T = direction * 500 * oilrate; // 前进为正,后退为负
		// if(Math.abs(speed)<2f){
		friction = -frictionfactor * pressionforce * speed * 2; // 摩擦力与速度成正比,方向相反
		// }
		// 得到坦克的正向方向向量与斜坡方向向量的夹角即可
		Tangle = cardirection.angleBetween(slope);
		float Tf = extraforce * (float) Math.cos(Tangle); // 重力的分力在坦克方向上的投影
		float Trecoil=cardirection.dot(recoil);   //后座力在前进方向上的分力
		F = T + friction + Tf+Trecoil;
		acceleration = F / totalmass;
		recoil.multLocal(-0.7f);

		// /////////////////////////////////////////////////////////侧向摩擦减速
		float sideT = -pressionforce * sidefactor * sidespeed;
		sideacceleration = sideT / totalmass;

	}

	/**
	 * 刷新前进速度,和横向速度
	 *
	 * @param time
	 */
	public void refreshspeed(float time) {
		speed = speed + acceleration * time;
		forward(speed);
		sidespeed = sidespeed + sideacceleration * time;
		strafeleft(sidespeed);
	}
	
	/**
	 * 创建声音对象
	 */
	private void createsound(){
		hitbybulletsound = AudioSystem.getSystem().createAudioTrack(getClass().getResource("/cn/netjava/robo3d/sound/explodeArea.ogg"),false);
		hitbybulletsound.setMaxAudibleDistance(1000);
		
		shootsound = AudioSystem.getSystem()
		.createAudioTrack("/cn/netjava/robo3d/sound/shoot.wav", false);
        shootsound.setType(TrackType.POSITIONAL);
        shootsound.setRelative(false);
        shootsound.setReferenceDistance(1f);
        shootsound.setVolumeChangeRate(0.2f);
        shootsound.setMaxAudibleDistance(1);

		changegearsound = AudioSystem.getSystem().createAudioTrack(getClass().getResource("/cn/netjava/robo3d/sound/gear_change1.wav"),false);
		changegearsound.setMaxAudibleDistance(1000);
		
		powersound=AudioSystem.getSystem().createAudioTrack(getClass().getResource("/cn/netjava/robo3d/sound/Engine1.wav"),true);
		powersound.setLooping(true);
		powersound.play();
		powersound.setVolume(0.4f);
		
		movesound=AudioSystem.getSystem().createAudioTrack(getClass().getResource("/cn/netjava/robo3d/sound/tankturn.wav"),true);
		movesound.setLooping(true);
		movesound.play();
		movesound.setVolume(0);
		
		jumpsound=AudioSystem.getSystem().createAudioTrack(getClass().getResource("/cn/netjava/robo3d/sound/jump.wav"),false);
		jumpsound.setVolume(soundvolume+0.2f);
		
		impactfloorsound=AudioSystem.getSystem().createAudioTrack(getClass().getResource("/cn/netjava/robo3d/sound/impactfloor2.wav"),false);
		impactfloorsound.setVolume(soundvolume);
		impactcarsound=AudioSystem.getSystem().createAudioTrack(getClass().getResource("/cn/netjava/robo3d/sound/impactcar.ogg"),false);
		impactcarsound.setVolume(soundvolume);
	}
	
	/**
	 * 刷新声音大小，根据与主角坦克的距离而定
	 * 
	 */
     private void refreshsoundvolume(){
    	 //主角坦克用默认
    	 if(!getName().equals("player")){
    	     float distance=0;
    		 for(int i=0;i<allothertanksinfo.size();i++){
    	    	if(allothertanksinfo.get(i).getName().equals("player")){
    	    		distance=allothertanksinfo.get(i).getLocaltranslation().distance(getLocalTranslation());
    	    		break;
    	    	}
    	     }
    		 if(distance<volumelimitdistance){
    			 soundvolume=(1-distance/volumelimitdistance)*maxvolume;
    		 }else{
    			 soundvolume=0;
    		 }
    	 
    		 hitbybulletsound.setVolume(soundvolume);
    	     shootsound.setVolume(soundvolume);
    	     changegearsound.setVolume(soundvolume);
    	     float powervolume=(oilrate/engineable)*soundvolume+0.1f;
    	     powersound.setVolume(powervolume);
    	     
    	     //坦克转向声音和前进声音，根据速度
    	     float movevolume=soundvolume*getspeed()/40f;
    	     movevolume=FastMath.abs(movevolume);
    	     if(movevolume<0.05)movevolume=0;
    	     movesound.setVolume(movevolume);
    	     
    	     jumpsound.setVolume(soundvolume);
    	     impactfloorsound.setVolume(soundvolume);
    	     impactcarsound.setVolume(soundvolume);
    	     
    	 }else{
    		 //如果是主角坦克
    	     float powervolume=(oilrate/engineable)*soundvolume+0.1f;
    	     powersound.setVolume(powervolume);
    	     
    	     float movevolume=soundvolume*getspeed()/10f;
    	     movevolume=FastMath.abs(movevolume);
    	     if(movevolume<0.05)movevolume=0;
    	     //System.out.println("movevolume:"+movevolume);
    	     movesound.setVolume(movevolume);
    	     
    	     
    	     
    	     
    	 }
     }
	
	
	/**
	 * 重新初始化
	 * @param display
	 */
	public void reinit(Input input){
		display=DisplaySystem.getDisplaySystem();
		createbase(); // 创建基座;
		this.setinput(input);
		this.createcase(display);
		this.createbullets(display);
	}

	/**
	 * 以一定速度向右旋转炮塔
	 */
	public void rightcasemate(float speed) {
		caserotaright.setActionSpeed(speed);
		caserotaright.performAction(input.getevent());
	}

	/**
	 * 子类实现智能的地方
	 *
	 */
	public void run() {
	}

	// 雷达扫描
	public void scan() {

	}

	/**
	 * 设置坡度角
	 *
	 * @return
	 */
	private void setAngle() {
		angle = vertical.angleBetween(normal);
		// System.out.println("angle:"+angle*FastMath.RAD_TO_DEG);
	}

	public void setCardirection(Vector3f cardirection) {
		this.cardirection = cardirection;
	}

	/**
	 * 设置前后进档位
	 */
	public void setdirection(int direction) {
		this.direction = direction;
	}

	public void setdisplay(DisplaySystem display) {
		this.display = display;
	}

	/**
	 * 设置合力
	 *
	 * @param F
	 */
	public void setF(float F) {
		this.F = F;
	}

	/**
	 * 设置摩擦力
	 *
	 * @param friction
	 */
	public void setfriction(float friction) {
		this.friction = friction;
	}

	/**
	 * 设置油门档位
	 *
	 * @param gear
	 */
	private void setGear(int gear) {
		Gear = gear;
		switch (Gear) {
		case 1:
			this.setMaxoilrate(engineable/3f);
			return;
		case 2:
			this.setMaxoilrate(2*engineable/3f);
			return;
		case 3:
			this.setMaxoilrate(engineable);
			return;
		}
	}

	public void setinput(Input input) {
		this.input = input;
	}

	public void setLeftdirection(Vector3f leftdirection) {
		this.leftdirection = leftdirection;
	}

	/**
	 * 设置当前油门最大限制
	 *
	 * @param maxoilrate
	 */
	public void setMaxoilrate(float currentmaxoil) {
		Maxoilrate = currentmaxoil;
	}

	/**
	 * 设置车体所在位置的法线
	 *
	 * @param
	 */
	private void setNormal() {
		tb.getSurfaceNormal(this.getLocalTranslation(), normal);
		normal = getunit(normal);
	}

	/**
	 * 设置斜坡方向向量
	 *
	 * @param
	 */
	private void setslope() {
		slope.setX(normal.getX());
		slope.setZ(normal.getZ());
		// 通过法线得到斜坡方向
		float y = (float) (-normal.getY() * Math.tan(angle) * Math.tan(angle));
		slope.setY(y);
		slope = getunit(slope);
	}

	/**
	 * 设置前进速度
	 *
	 * @param speed
	 */
	public void setspeed(float speed) {
		if (speed < 0.02)
			speed = 0;
		this.speed = speed;

	}

	// 发射子弹
	public void shoot() {
		if (bulletnum > 0) { // 没子弹不能打
			// 激活一颗子弹
			for (int i = 0; i < bullets.size(); i++) {
				if (!bullets.get(i).islive()) { // 如果不是睡眠状态
					bullets.get(i).setactive();
					bulletnum--;

					//给坦克添加后座力
                    recoil=gundirection.mult(-50000);
					// 添加声音
					 shootsound.play();
					 return;
				}
			}
		}
	}

	// 冒烟
	private void smoke() {

	}

	/**
	 * 启动事件监控器,创建事件对象,在update 方法中循环一次
	 */
	private void startlistener() {
		// 先创建事件对象,然后把事件对象和监听器对象加入到探测器中
		// ////////////////////////撞车事件
		impactcarevent = new ImpactCarEvent(info, allothertanksinfo);

		// ///////////////////////火烧事件
		hitbyfireevent = new HitByFireEvent(info, allothertanksinfo);

		// //////////////////////中弹事件
		hitbybulletevent = new HitByBulletEvent(info, allothertanksinfo);

		startdetect = true;

	}

	/**
	 * 以一定速度左侧移
	 *
	 * @return
	 */
	public void strafeleft(float speed) {
		strafeleft.setSpeed(speed);
		strafeleft.performAction(input.getevent());
	}

	/**
	 * 以一定速度右侧移
	 *
	 * @return
	 */
	public void straferight(float speed) {
		straferight.setSpeed(speed);
		straferight.performAction(input.getevent());
	}

	/**
	 * 向左转
	 *
	 * @return
	 */
	public void turnleft() {
		left.performAction(input.getevent());
		//carturn.play();
	}

	/**
	 * 向右转
	 *
	 * @return
	 */
	public void turnright() {
		right.performAction(input.getevent());
		//carturn.play();
	}

	/**
	 * 刷新坦克参数,与主场景同步
	 *
	 * @param interpolation
	 * @param tb
	 */
	public void update(float interpolation, TerrainBlock tb) {
		this.tb = tb;
		keepthison(interpolation); // 使本物体在地形上
		keepoilrate();
		oilratedrift.performAction(input.getevent());
		refreshpower();
		setAngle();
		setslope();
		ajustpose(); // 调整坦克姿态,各种指向
		setNormal(); // 设置坦克位置地形的法线
		// settilt(interpolation); //设置倾角
		detect(); // 判断是否有事件发生，并作出反应
		// ////////////////////////////////////////////////////////////////////
		// ////////////////////////////////////////////////////////////////////
		oil = oil - oilrate * interpolation / 4;
		if (oil <= 0.1 && oil != 0) {// 不让它执行第二次
			System.out.println("没油了!");
			oil = 0;
			oilrate = 0;
			T = 0;
		}
		// /////////////////////////////////////////////////////////////////////
		// /////////////////////////////////////////////////////////////////////
		refreshinfo();// 刷新坦克信息
		if (startlistener) { // 因为要等一些参数初始化
			startlistener();
			startlistener = false;
		}
		// /////////////////////////////////////////////////////////////////////
		// /////////////////////////////////////////////////////////////////////
		// 控制子弹的轨迹,直线运动的
		for (int i = 0; i < bullets.size(); i++) {
			if (bullets.get(i).islive()) {
				
				bullets.get(i).update(interpolation);
				
			}
		}
		//刷新声音大小
		refreshsoundvolume();
	}
}
